package com.example.demoes.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@Component
public class JwtUtils {
    @Value("${spring.security.jwt.key}")
    String key;
    @Value("${spring.security.jwt.expire}")
    int expire;
     @Resource
    StringRedisTemplate template;
    public  boolean invalidateJwt(String headerToken) {
        String token = this.converToken(headerToken);
        if (token == null) return false;
        Algorithm algorithm = Algorithm.HMAC256(key);
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();
        try {
           DecodedJWT jwt = jwtVerifier.verify(token);
           String id =  jwt.getId();
           return deleteToken(id,jwt.getExpiresAt());
        } catch (JWTVerificationException e) {
           return  false;
        }
    }
    private boolean deleteToken(String uuid,Date time){
       if(this.isInvalidToken(uuid)){
           return false;
       }
         Date now =  new Date();
          long expire = Math.max( time.getTime()  - now.getTime(),0) ;
         template.opsForValue().set(Const.JWT_BLACK_LIST+uuid,"",expire,TimeUnit.MILLISECONDS );
         return  true;
    }
    private boolean isInvalidToken(String uuid){
        return  Boolean.TRUE.equals(template.hasKey(Const.JWT_BLACK_LIST+uuid));
    }
    public DecodedJWT resolveJwt(String headerToken){
        String token = this.converToken(headerToken); //解析token，取出前七位；查看token是否为空
        if(token == null ){  //判断是否为空
            return  null;
        }
        Algorithm algorithm = Algorithm.HMAC256(key); //指定算法
        JWTVerifier jwtVerifier = JWT.require(algorithm).build(); //使用算法指定验证实体类
        try{
            DecodedJWT verify =  jwtVerifier.verify(token); //验证是否有被篡改
            if(this.isInvalidToken(verify.getId())){
                return  null;
             }
            Date expiresAt = verify.getExpiresAt(); //查看过期时间
            return  new  Date().after(expiresAt) ? null : verify; //国企返回空
        } catch (JWTVerificationException e){  //捕获修改异常
             return  null;
         }
    }
    public  String createJwt(UserDetails details,int id,String username){
        Algorithm algorithm = Algorithm.HMAC256(key);
        Date expire = this.expireTime();
        return JWT.create()
                .withJWTId(UUID.randomUUID().toString())
               .withClaim("id",id)
                .withClaim("name",username)
                .withClaim("authorities",details.getAuthorities().stream().map(GrantedAuthority::getAuthority).toList())
                .withExpiresAt(expire) //过期的时间
                .withIssuedAt(new Date()) //颁发时间
                .sign(algorithm); //签名
    }
   public Date expireTime(){
        Calendar calendar  = Calendar.getInstance();
        calendar.add(Calendar.HOUR,expire * 24 );
        return  calendar.getTime();
    }
    public UserDetails toUser(DecodedJWT jwt){
        Map<String, Claim> claims =
                jwt.getClaims();
        return  User
               .withUsername(claims.get("name").asString())
               .password("*******")
               .authorities(claims.get("authorities").asArray(String.class))
               .build();
    }
    public Integer toId(DecodedJWT jwt){
        Map<String, Claim> claims =
                jwt.getClaims();
        return  claims.get("id").asInt();
    }
    private String converToken(String headerToken){  //判断token是否合法，并且切割除除了Bearer的Token
        if(headerToken == null || !headerToken.startsWith("Bearer ")){
                 return null;
         }
           return  headerToken.substring(7);
    }
}
